﻿/*
   Copyright 2011 Softisis

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/


using System;
using System.Linq.Expressions;
using FOM.Interfaces;

namespace FOM.Impl.CompactExtensions
{

    /// <summary>
    /// Extension of mapping node interface to support short name methods.
    /// </summary>
    public static class ShortNamesNodeImpl
    {
        /// <summary>
        /// Compact version of Map.
        /// Create a child mapping on "this" mapping.
        /// </summary>
        /// <typeparam name="TPropertyS">Type of source property.</typeparam>
        /// <typeparam name="TPropertyD">Type of targeted property</typeparam>
        /// <param name="expsrc">Expression pointing at the source property</param>
        /// <param name="expdst">Expression pointing at the target property</param>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <param name="node">Mapping node</param>
        /// <returns>A new mapping for these two properties.</returns>
        public static IMappingNode<TPropertyS, TPropertyD> MP<TPropertyS, TPropertyD, TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node,
            Expression<Func<TSrc, TPropertyS>> expsrc,
            Expression<Func<TDst, TPropertyD>> expdst)
        {
            return node.Map(expsrc, expdst);
        }

        /// <summary>
        /// Compact version of Map.
        /// Create a child mapping on "this" mapping. The source and destination are the same.
        /// </summary>
        /// <typeparam name="TProperty">Property of the source/destination</typeparam>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <param name="node">Mapping node</param>
        /// <param name="expr">Expression to source and destination property</param>
        /// <returns>A new mapping for these two properties.</returns>
        public static IMappingNode<TProperty, TProperty> MP<TProperty, TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node,
            Expression<Func<TSrc, TProperty>> expr)
        {
            return node.Map(expr);
        }


        /// <summary>
        /// Compact version of Exclude.
        /// Define some exclusion path. Can be usefull with IConverter that deals with massive copies.
        /// Exclusion is taken prior to a Map.
        /// </summary>
        /// <typeparam name="TPropertyS">Type of source property.</typeparam>
        /// <typeparam name="TPropertyD">Type of targeted property</typeparam>
        /// <param name="node">Mapping node</param>
        /// <param name="expsrc">Expression pointing at the source property</param>
        /// <param name="expdst">Expression pointing at the target property</param>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <returns>"this"</returns>
        public static IMappingNode<TSrc, TDst> EX<TPropertyS, TPropertyD, TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node,
            Expression<Func<TSrc, TPropertyS>> expsrc,
            Expression<Func<TDst, TPropertyD>> expdst)
        {
            return node.Exclude(expsrc, expdst);
        }


        /// <summary>
        /// Compact version of Exclude.
        /// Define some exclusion path on the same path for source and target object.
        /// </summary>
        /// <typeparam name="TPropertyS">Type of source property.</typeparam>
        /// <param name="expsrc">Expression pointing at the source property</param>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <param name="node">Mapping node</param>
        /// <returns>"this"</returns>
        public static IMappingNode<TSrc, TDst> EX<TPropertyS, TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node,
            Expression<Func<TSrc, TPropertyS>> expsrc)
        {
            return node.Exclude(expsrc);
        }

        /// <summary>
        /// Compact version of NewInstance.
        /// Tells the kernel to have an new instance of the pointed object
        /// to be created for this mapping, instead of using the original object.
        /// On the root mapping, this is also allowed. But when the mapping is run, if a destination
        /// object is provided, it will be ignored.
        /// This call is the same as NewInstance(false)
        /// </summary>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <param name="node">Mapping node</param>
        /// <returns>"this"</returns>
        public static IMappingNode<TSrc, TDst> NI<TSrc, TDst>(this IMappingNode<TSrc, TDst> node)
        {
            return node.NewInstance();
        }


        /// <summary>
        /// Compact version of NewInstance.
        /// Tells the kernel to have an new instance of the pointed object
        /// to be created for this mapping, instead of using the original object.
        /// On the root mapping, this is also allowed. But when the mapping is run, if a destination
        /// object is provided, it will be ignored.
        /// The parameter reuseCached tells the kernel wether or not an existing previously created 
        /// instance must be reused or not. (for the same source reference).
        /// </summary>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <param name="node">Mapping node</param>
        /// <param name="reuseCached">If true, the instance is taken from cache if not already created, or put in cache for reuse.
        /// Use this parameter to maintain references.</param>
        /// <returns>"This"</returns>
        public static IMappingNode<TSrc, TDst> NI<TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node,
            bool reuseCached
            )
        {
            return node.NewInstance(reuseCached);
        }



        /// <summary>
        /// Compact version of GoTo.
        /// Go into the objects. It does not create a mapping, but a new startpoint from the path.
        /// NewInstance and OverrideingTypes can be applied on the "GoTo" returned node.
        /// </summary>
        /// <typeparam name="TPropertyS">Type of source property</typeparam>
        /// <typeparam name="TPropertyD">Type of target property</typeparam>
        /// <param name="expsrc">Source expression to seek to</param>
        /// <param name="expdst">target expression to seek to</param>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <param name="node">Mapping node</param>
        /// <returns>The mapping seek to</returns>
        public static IMappingNode<TPropertyS, TPropertyD> GT<TPropertyS, TPropertyD, TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node,
            Expression<Func<TSrc, TPropertyS>> expsrc,
            Expression<Func<TDst, TPropertyD>> expdst)
        {
            return node.GoTo(expsrc, expdst);
        }


        /// <summary>
        /// Compact version of OverrideTargetType.
        /// Tells the kernel to use another type instead of the initial target one.
        /// </summary>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <typeparam name="TReplacement">Replacement type for the target</typeparam>
        /// <param name="node">Mapping node</param>
        /// <returns>"This"</returns>
        public static IMappingNode<TSrc, TReplacement> TT<TReplacement, TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node)
        {
            return node.OverrideTargetType<TReplacement>();
        }


        /// <summary>
        /// Compact version of OverrideSourceType.
        /// Tells the kernel to use another type instead of the initial source one.
        /// </summary>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <typeparam name="TReplacement">Replacement type for the source</typeparam>
        /// <param name="node">Mapping node</param>
        /// <returns>"This"</returns>
        public static IMappingNode<TReplacement, TDst> ST<TReplacement, TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node
            )
        {
            return node.OverrideSourceType<TReplacement>();
        }

        /// <summary>
        /// Compact version of UseConverter.
        /// Tells the kernel that a specific converter must be used to translate the source
        /// to destination.
        /// </summary>
        /// <param name="converter">The converter to use to convert source to target. CF. IConverter for more informations.</param>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <param name="node">Mapping node</param>
        /// <returns>"this"</returns>
        public static IMappingNode<TSrc, TDst> CV<TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node,
            IConverter converter)
        {
            return node.UseConverter(converter);
        }

        /// <summary>
        /// Compact version of UseCondition.
        /// Make the mapping a conditonnal mapping. If ICondition.CanApplyMapping returns true, 
        /// the target value is affected. Otherwise, it's ignored, the target is left "as is".
        /// </summary>
        /// <param name="cond">This condition implementation</param>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <param name="node">Mapping node</param>
        /// <returns>True if the mapping can be applied, false otherwise.</returns>
        public static IMappingNode<TSrc, TDst> IF<TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node,
            ICondition cond)
        {
            return node.UseCondition(cond);
        }


        /// <summary>
        /// Compact version of Reverse.
        /// Reverse the mapping. Applyed on a node &lt;TSrc, TDst&gt;, the result is a node &lt;TDst, TSrc&gt;.
        /// This methods is recursive. The name given on a root node is [name]Reverse.
        /// </summary>
        /// <typeparam name="TSrc">The source type of the original mapping</typeparam>
        /// <typeparam name="TDst">The target type of the original mapping</typeparam>
        /// <param name="node">The reversed maping. Source and tarrget types are not reversed.</param>
        /// <returns></returns>
        public static IMappingNode<TDst, TSrc> RV<TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node)
        {
            return node.Reverse();
        }


        /// <summary>
        /// Compact version of Remove.
        /// Remove a node, according to the given path.
        /// </summary>
        /// <typeparam name="TPropertyS">Type of source property.</typeparam>
        /// <typeparam name="TPropertyD">Type of targeted property</typeparam>
        /// <param name="expsrc">Expression pointing at the source property</param>
        /// <param name="expdst">Expression pointing at the target property</param>
        /// <typeparam name="TSrc">Source type of the parent node</typeparam>
        /// <typeparam name="TDst">Target type of the parent node</typeparam>
        /// <param name="node">Mapping node</param>
        /// <returns></returns>
        public static bool RM<TPropertyS, TPropertyD, TSrc, TDst>(
            this IMappingNode<TSrc, TDst> node,
            Expression<Func<TSrc, TPropertyS>> expsrc,
            Expression<Func<TDst, TPropertyD>> expdst)
        {
            return node.Remove(expsrc, expdst);
        }
    }
}
